package com.ea.service.impl;

import com.ea.common.constant.BaseNumConstant;
import com.ea.common.constant.RedisKeyConstants;
import com.ea.common.enums.AccountStatusEnums;
import com.ea.common.enums.OperationResultCode;
import com.ea.common.exception.ServiceException;
import com.ea.common.util.IdWorker;
import com.ea.common.util.MD5Util;
import com.ea.common.util.RedisUtil;
import com.ea.common.util.TokenUtil;
import com.ea.domain.dto.AdminDTO;
import com.ea.domain.dto.LoginCreateDTO;
import com.ea.domain.dto.LoginDTO;
import com.ea.domain.dto.LoginUpdateDTO;
import com.ea.domain.entity.AdminInfo;
import com.ea.domain.query.AdminQueryDTO;
import com.ea.holder.AdminHolderInfo;
import com.ea.mapper.AdminInfoMapper;
import com.ea.service.IAdminInfoService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * @author NAME-L
 * @Description TODO
 * @className IAdminInfoServiceImpl
 * @date 2022-12-21 22:28:12
 */
@Service
public class IAdminInfoServiceImpl implements IAdminInfoService {

    private static final Logger logger = LoggerFactory.getLogger(IAdminInfoServiceImpl.class);

    @Autowired
    private AdminInfoMapper adminInfoMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public AdminDTO adminLoginIn(LoginDTO loginDTO) {
        AdminDTO adminDTO = new AdminDTO();
        String loginAccount = loginDTO.getLoginAccount();
        String loginPassword = loginDTO.getLoginPassword();
        // String    null || ""
        // if(判断条件){业务逻辑。。} true
        if (StringUtils.isEmpty(loginAccount) || StringUtils.isEmpty(loginPassword)) {
            throw new ServiceException(OperationResultCode.PARAMETER_ERROR);
        }
        // 查询数据库判断账号状态
        AdminInfo adminInfo = adminInfoMapper.selectAdminInfoByAccount(loginAccount);
        if (adminInfo == null) {
            throw new ServiceException(OperationResultCode.ACCOUNT_NOT_EXISTS);
        }
        // true  -> !true  => false
        if (!AccountStatusEnums.NORMAL.getCode().equals(adminInfo.getStatus())) {
            throw new ServiceException(OperationResultCode.ACCOUNT_STATUS_IS_ABNORMAL.getCode(), String.format(OperationResultCode.ACCOUNT_STATUS_IS_ABNORMAL.getMsg(), loginAccount));
        }
        Integer count = (Integer) redisUtil.get(RedisKeyConstants.SUBJECT_KEY + loginAccount + RedisKeyConstants.ADMIN_LOGIN_FAIL);
        if (count == null) {
            count = 0;
        }
        // 先判断是否有输入错误次数记录，3次则不允许登录
        if (count == 3) {
            throw new ServiceException(OperationResultCode.ACCOUNT_IS_FORBIDDEN);
        }
        // 通过MD5工具判断输入的密码与数据库存储的密码是否符合
        boolean conform = MD5Util.verify(loginPassword, adminInfo.getLoginPassword());
        if (!conform) {
            logger.error("MD5密码校验失败");
            // 如果不为 0 的情况，说明已经有输入错误的情况
            if (count == 0) {
                count++;
                redisUtil.set(RedisKeyConstants.SUBJECT_KEY + loginAccount + RedisKeyConstants.ADMIN_LOGIN_FAIL, count, 60 * 10);
            } else {
                long expireTime = redisUtil.getExpire(RedisKeyConstants.SUBJECT_KEY + loginAccount + RedisKeyConstants.ADMIN_LOGIN_FAIL);
                count++;
                redisUtil.set(RedisKeyConstants.SUBJECT_KEY + loginAccount + RedisKeyConstants.ADMIN_LOGIN_FAIL,count , expireTime);
            }
            throw new ServiceException(OperationResultCode.ACCOUNT_PASSWORD_ERROR.getCode(), OperationResultCode.ACCOUNT_PASSWORD_ERROR.getMsg() + "今日可重试次数还剩" + (3 - count) + "次");
        }

        // 记录token
        String token = TokenUtil.tokenGenerator(adminInfo.getAdminId());
        redisUtil.set(RedisKeyConstants.SUBJECT_KEY + adminInfo.getAdminId() + RedisKeyConstants.ADMIN_LOGIN_TOKEN, token, 60 * 15);
        // 登录成功后删除失败记录
        boolean hasFail = redisUtil.hasKey(RedisKeyConstants.SUBJECT_KEY + loginAccount + RedisKeyConstants.ADMIN_LOGIN_FAIL);
        if (hasFail) {
            redisUtil.del(RedisKeyConstants.SUBJECT_KEY + loginAccount + RedisKeyConstants.ADMIN_LOGIN_FAIL);
        }
        BeanUtils.copyProperties(adminInfo, adminDTO);
        adminDTO.setToken(token);
        return adminDTO;
    }

    @Override
    public void adminLoginOut() {
        Long adminId = AdminHolderInfo.getAdminId();
        AdminInfo adminInfo = adminInfoMapper.selectAdminInfoByAdminId(adminId);
        if (adminInfo == null) {
            throw new ServiceException(OperationResultCode.SYSTEM_ERROR);
        }
        String redisKey = RedisKeyConstants.SUBJECT_KEY + adminInfo.getAdminId() + RedisKeyConstants.ADMIN_LOGIN_TOKEN;
        if (redisUtil.hasKey(redisKey)) {
            redisUtil.del(redisKey);
        }

    }

    @Override
    public PageInfo<AdminInfo> getAdminInfoList(AdminQueryDTO queryDTO) {
        Integer pageIndex = queryDTO.getPageIndex() == null ? BaseNumConstant.NUM_1 : queryDTO.getPageIndex();
        Integer pageSize = queryDTO.getPageSize() == null ? BaseNumConstant.NUM_20 : queryDTO.getPageSize();
        PageHelper.startPage(pageIndex, pageSize);
        List<AdminInfo> adminInfoList = adminInfoMapper.selectAllByCondition(queryDTO);
        return new PageInfo<>(adminInfoList);
    }

    @Override
    public Map<String, Object> createAdminInfo(LoginCreateDTO createDTO) {
        Map<String, Object> returnMap = new HashMap<>();
        String loginAccount = createDTO.getLoginAccount();
        Integer count = adminInfoMapper.selectCountByLoginAccount(loginAccount);
        if (count != 0) {
            throw new ServiceException(OperationResultCode.ACCOUNT_IS_EXISTS);
        }
        AdminInfo adminInfo = new AdminInfo();
        BeanUtils.copyProperties(createDTO, adminInfo);
        adminInfo.setAdminId(IdWorker.nextId());
        adminInfo.setStatus(AccountStatusEnums.BE_ACTIVATE.getCode());
        String password = randomPassword();
        String secretPassword = MD5Util.generate(password);
        adminInfo.setLoginPassword(secretPassword);
        adminInfoMapper.insertAdminInfo(adminInfo);
        returnMap.put("password", password);
        return returnMap;
    }

    @Override
    public void updateAdmin(LoginUpdateDTO updateDTO) {
        Long adminId = updateDTO.getAdminId();
        logger.info("要更新的管理员id：{}", adminId);
        AdminInfo adminInfo = adminInfoMapper.selectAdminInfoByAdminId(adminId);
        if (adminInfo == null) {
            throw new ServiceException(OperationResultCode.ACCOUNT_NOT_EXISTS);
        }
        if (!AccountStatusEnums.NORMAL.getCode().equals(adminInfo.getStatus())) {
            throw new ServiceException(OperationResultCode.ACCOUNT_UPDATE_FROBIDDEN.getCode(), String.format(OperationResultCode.ACCOUNT_UPDATE_FROBIDDEN.getMsg(), AccountStatusEnums.getStatusDesc(adminInfo.getStatus())));
        }
        adminInfoMapper.updateAdminInfo(updateDTO);
    }

    @Override
    public void writeOffAdmin(Long adminId) {
        logger.info("需要注销的管理员id：{}", adminId);
        AdminInfo adminInfo = adminInfoMapper.selectAdminInfoByAdminId(adminId);
        if (adminInfo == null) {
            throw new ServiceException(OperationResultCode.ACCOUNT_NOT_EXISTS);
        }
        adminInfoMapper.updateWriteOffAdmin(adminId);
    }

    @Override
    public void changePassword(String oldPassword, String newPassword) {
        Long adminId = AdminHolderInfo.getAdminId();
        logger.info("需要修改密码的管理员id：{}", adminId);
        AdminInfo adminInfo = adminInfoMapper.selectAdminInfoByAdminId(adminId);
        if (adminInfo == null) {
            throw new ServiceException(OperationResultCode.ACCOUNT_NOT_EXISTS);
        }
        String password = adminInfo.getLoginPassword();
        boolean success = MD5Util.verify(oldPassword, password);
        if (!success) {
            throw new ServiceException(OperationResultCode.ACCOUNT_PASSWORD_ERROR);
        }
        // 新密码
        String newEncryptPassword = MD5Util.generate(newPassword);
        logger.info("修改后加密的密码为：{}", newEncryptPassword);
        adminInfoMapper.updateAccountPassword(adminId, newEncryptPassword);
    }

    @Override
    public Map<String, Object> resetPassword(Long adminId) {
        AdminHolderInfo.getAuth();
        Map<String, Object> returnMap = new HashMap<>();
        logger.info("重置密码的管理员id：{}", adminId);
        String newPassword = randomPassword();
        String encryptPassword = MD5Util.generate(newPassword);
        adminInfoMapper.updateAccountPassword(adminId, encryptPassword);
        returnMap.put("password", newPassword);
        String redisKey = RedisKeyConstants.SUBJECT_KEY + adminId + RedisKeyConstants.ADMIN_LOGIN_TOKEN;
        if (redisUtil.hasKey(redisKey)) {
            redisUtil.del(redisKey);
        }
        return returnMap;
    }

    private String randomPassword() {
        Random random = new Random();
        return String.valueOf(random.nextInt(999999) + 1);
    }

}
